htmx notes

Must Watch!



MustWatch

♦htmx Examples htmx examples using htmx


HTMX Examples

What Is HTMX?
HTMX Overview: Syntax, Features, and Capabilities
 Request Triggers
 Query Parameters and Body Data
 Result Content Handling
HTMX in Action: Integration With ApostropheCMS
 Getting Started
 Integrating HTMX
 Adding a Load More Button With HTMX
 Using HTMX to Implement Infinite Scrolling
 Achieving Live Content Filtering Through HTMX

HTMX aims to provide access to modern browser functionality directly in HTML code, without a single line of JavaScript.

What Is HTMX?

HTMX is a small, dependency-free, extendable library that allows you to access modern browser features directly from HTML, instead of using JavaScript. Specifically, it gives you access to AJAX (i.e., fetching content without reloading the whole page), CSS Transitions, WebSockets, and Server Sent Events directly via HTML attributes. An example! Take a look at this snippet: <button hx-get="/api/v1/hello-world" hx-swap="outerHTML">Click Me</button> The special hx-get and hx-swap attributes tell HTMX: “When a user clicks on this button, instruct the browser to perform an AJAX request to the ‘/api/v1/hello-world’ endpoint, and replace the entire button with the HTML content returned by the server” In JavaScript, achieving the same result would take dozens of lines of code. That is the power of HTMX!

HTMX Overview: Syntax, Features, and Capabilities

The core idea behind HTMX is the ability to send AJAX requests directly from HTML, with no JavaScript involved. This is possible thanks to the following attributes: hx-get: To perform a GET request to the given URL. hx-post: To perform a POST request to the given URL. hx-put: To perform a PUT request to the given URL. hx-patch: To perform a PATCH request to the given URL. hx-delete: To perform a DELETE request to the given URL. When a specific event is triggered, the HTML element involving one of these HTMX attributes will make an AJAX request of the specified type to the given URL. Consider the example below: <button hx-post="/api/v1/products/buy">Buy</button> This tells the browser: “When a user clicks on the <button>, make a POST request to the URL ‘/api/v1/products/buy’ and load the response into the inner HTML of the <button>”

 Request Triggers

By default, AJAX requests made by HTMX are triggered by the “natural” event associated with the HTML element: change: For <input>, <textarea> and <select> elements. submit: For the <form> element. click: For every other element. Going back to the snippet seen earlier, it should now be clear why the action that triggers the request is a click, even if not specified. To modify the default trigger behavior, you can use the hx-trigger attribute to set which HTML event will cause the request. Check out the list of events supported by HTML. Take a look at the example below: <span hx-get="/api/v1/products" hx-trigger="mouseenter">Hover Me!</span> This tells the browser: "When a user moves the mouse over the <span>, perform a GET request to the URL ‘/api/v1/products’ and render the response in the inner HTML of the <span>” Keep in mind that hx-trigger also supports modifiers and filters to tailor the triggering logic to your needs. Plus, HTMX provides the following special events: load: Fires when the element is loaded for the first time. revealed: Fires once when the element is scrolled into the viewport. intersect: Fires once when the element intersects with the viewport. As opposed to revealed, it accepts an optional CSS selector of the root element for intersection and a float number between 0.0 and 1.0 to indicate the amount of intersection to trigger the event on.

 Query Parameters and Body Data

The way HTMX handles parameters and body data changes depending on the type of the request: GET requests: The query parameters should be specified in the URL passed to hx-get. By default, hx-get does not automatically include any parameters to the request. Anyway, you can control that with the hx-params attribute as explained in the documentation. Non-GET requests: If an element is a <form>, the body will include the values of all inputs within it, using their name attribute as the parameter name. If it is not a <form>, the body will include the values of all the inputs of the nearest enclosing <form>. Otherwise, if it has a value attribute, it will be used in the body. When the default behavior is not enough, the hx-include and hx-params attributes allows you to control which values and which parameters to set, respectively. Otherwise, you can programmatically modify the body fields by listening to the htmx:configRequest event.

 Result Content Handling

By default, HTMX replaces the inner HTML of the element firing the request with the HTML returned by the AJAX call. This means that HTMX-compliant AJAX endpoints should return HTML code. To change the swap strategy, use the hx-swap attribute. That supports the following values: innerHTML: Replace the inner HTML of the target element. outerHTML: Replace the entire target element with the response. beforebegin: Insert the response before the target element. afterbegin: Insert the response before the first child of the target element. beforeend: Insert the response after the last child of the target element. afterend: Insert the response after the target element. delete: Delete the target element regardless of the response. none: Does not append the content from the response. You can change the target element the swap logic refers to with the hx-target attribute, which accepts a CSS selector. Note that the attribute supports multiple triggers, each one separated by comma. Focus now on the following snippet: <button hx-post="/api/v1/comments" hx-trigger="click" hx-swap=".comments" hx-target="afterend" > Comment </button> This tells the browser: “When a user clicks the <button>, perform a POST request to the URL ‘/api/v1/comments’ and add the resulting HTML to the .comments element”

HTMX in Action: Integration With ApostropheCMS

You now know what HTMX is, why it was created, and what it brings to the table. All that remains is to see it in action in a real-world example. What better way to do that than by integrating it with Apostrophe? If you are not familiar with this technology, ApostropheCMS is an open-source CMS and website builder built on top of modern technologies such as MongoDB and Node.js. The starting point will be the blog application built in the “How to Build a Blog with the Apostrophe Blog Module” tutorial. You will learn how to add HTMX and use it to achieve the following dynamic interactions: “Load More” functionality Infinite scroll loading Live content filtering Let’s dive in!

 Getting Started

First, make sure to meet ApostropheCMS's system requirements. Next, launch the command below to clone the GitHub repository of the blog application you will soon extend with HTMX: git clone https://github.com/Tonel/apostrophe-blog Install the project’s dependencies: npm install Then, fire the following command to build the ApostropheCMS UI and start up the blog: npm run dev Open https://localhost:3000 in the browser and you should see:
HTMX Apostrophe UI
Follow the instructions, log in, and get familiar with the application. Play with the UI and populate the blog with several posts. You can then find the blog's home page at http://localhost:3000/blog.
htmx blog example
Great! If you want to learn more about how this application works and was built, take a look at our tutorial.

 Integrating HTMX

As stated in the documentation, integrating HTMX into an application boils down to adding a <script> tag to the document <head>. No build tools or special configurations are required. The fastest way to get going is to load the library via a CDN: <script src="https://unpkg.com/htmx.org@1.9.6" integrity="sha384-FhXw7b6AlE/jyjlZH5iHa/tTe9EpJ1Y55RjcgPbjeWMskSxZt1v9qkxLJWNJaGni" crossorigin="anonymous"></script> The goal of this section is to use HTMX to add dynamic interactions to the blog home page. So, you need to add the <script> instruction to the HTML document of that page. To add HTMX to the blog home page, follow the /modules/@apostrophecms/blog-page/views/ path and open the index.html file. Paste the following line after the title block: {% block extraHead %} <script src="https://unpkg.com/htmx.org@1.9.6" integrity="sha384-FhXw7b6AlE/jyjlZH5iHa/tTe9EpJ1Y55RjcgPbjeWMskSxZt1v9qkxLJWNJaGni" crossorigin="anonymous"></script> {% endblock %} extraHead is a block from the ApostropheCMS core layout template that allows you to add HTML elements at the end of the <head> tag. If you instead want to have HTMX in all pages, you can add it to your project's dependencies with: npm install htmx.org Then, import it in the modules/asset/ui/src/index.js file: import 'htmx.org'; export default () => { // your own project-level JS... }; Open http://localhost:3000/blog in the browser and inspect its source code. You should see the following HTML: <!DOCTYPE html> <html lang="en" > <head> <link href="/apos-frontend/default/apos-bundle.css" rel="stylesheet" /> <title>My Fantastic Blog </title> <meta name="viewport" content="width=device-width, initial-scale=1"> <script src="https://unpkg.com/htmx.org@1.9.6" integrity="sha384-FhXw7b6AlE/jyjlZH5iHa/tTe9EpJ1Y55RjcgPbjeWMskSxZt1v9qkxLJWNJaGni" crossorigin="anonymous"></script> </head> <!-- Omitted for brevity... --> Well done! The HTMX dependency script was added as required.

 Adding a Load More Button With HTMX

Right now, when the blog has more than 10 posts, the home page shows a pagination element.
htmx blog index
Click on one of these buttons, and you will be redirected to the selected page. For example, “2” brings you to /blog?page=2. What if you wanted to replace that interaction with a “Load More” button? Thanks to HTMX, that will take only a few lines of code! When the “Load More” button is clicked, the page should perform an AJAX request to retrieve the HTML to render other blog post cards. You could think of using HTMX to make the button target the /blog?page=2 endpoint and swap the current content with the retrieved HTML. However, keep in mind that /blog?page=2 returns the entire HTML of a new page. Following this approach is not recommended, as you ideally want to replace only a small portion of the page not the all the page. Specifically, you want to swap the “Load More” button with the new blog post tabs. To get close to the goal, you can take advantage of the aposRefresh=1 parameter. This query parameter instructs ApostropheCMS to return the rendered HTML of the inner template, excluding the wrapping markup. For example, the /blog?page=2&aposRefresh=1 endpoint returns something like: <div class="bg-container"> <h1 class="bg-h1">My Fantastic Blog</h1> <h3>Filters</h3> <ul class="bg-filter-list"> <li> <a href="/blog?year=2023">2023</a> </li> <li> <a href="/blog?year=2022">2022</a> </li> <li> <a href="/blog?year=2021">2021</a> </li> <li> <a class="is-active" href="/blog">All</a> </li> </ul> <h3>Blog post</h3> <div class="bg-preview-card"> <div class="bg-preview-date"> Released on September 4, 2022 </div> <div class="bg-preview-title"> <a href="/blog/lorem-ipsum-8">Lorem Ipsum 8</a> </div> </div> <div class="bg-preview-card"> <div class="bg-preview-date"> Released on August 2, 2022 </div> <div class="bg-preview-title"> <a href="/blog/lorem-ipsum-12">Lorem Ipsum 12</a> </div> </div> <!-- Omitted for brevity... --> </div> Much better! As you can see, this HTML involves only a partial section of the page. At the same time, it still includes the title and filter elements. To ignore them, you can change the index.html file so that it behaves differently based on the presence of a custom query parameter. Achieve that by updating the rendering logic inside the main block of /modules/@apostrophecms/blog-page/views/index.html as follows: {% block main %} {% if data.query.showOnlyList != "1" %} <div class="bg-container"> <h1 class="bg-h1">{{ data.page.title }}</h1> <h3>{{ __t('aposBlog:filters') }}</h3> {% render filters.render({ filters: data.piecesFilters, query: data.query, url: data.page._url }) %} <h3>{{ __t('aposBlog:pluralLabel') }}</h3> {{ renderBlogList() }} </div> {% else %} {{ renderBlogList() }} {% endif %} {% endblock %} Now, when the showOnlyList=1 query parameter is present, the endpoint for the blog home page will return only the list of blog posts. Otherwise, it will return the entire page as before. You may be wondering what renderBlogList() is. This is a custom Nunjucks macro that renders the list of blog post cards and the “Load More” button: {% set page = data.query.page | default(1) | int %} {% for piece in data.pieces %} <div class="bg-preview-card"> <div class="bg-preview-date"> {{ __t('aposBlog:releasedOn') }} {{ piece.publishedAt | date('MMMM D, YYYY') }} </div> <div class="bg-preview-title"> <a href="{{ piece._url }}">{{ piece.title }}</a> </div> </div> {% endfor %} <div class="load-more-div"> {% if page != data.totalPages %} <button hx-get="/blog?page={{page + 1}}&year={{data.query.year}}&showOnlyList=1&aposRefresh=1" hx-target=".load-more-div" hx-swap="outerHTML" > Load More </button> {% endif %} </div> {% endmacro %} Focus on the .load-more-div HTML element. That is where the HTMX magic happens! page is a variable that stores the current page of the blog posts to render. If there are still some blogs to load, the “Load More” button is added to the page. When the user clicks it, the webpage makes an AJAX request to the endpoint specified in hx-get. This will return the rendered HTML with the list of the posts related to the next page, considering the optional year filter. HTMX will then replace the outer HTML of the .load-more-div element with that content. Put it all together, and you will get: <!-- /modules/@apostrophecms/blog-page/views/index.html --> {% extends data.outerLayout %} {% import "filters.html" as filters %} {% import "@apostrophecms/pager:macros.html" as pager with context %} {% block title %}{{ data.page.title }} {% endblock %} {% block extraHead %} <script src="https://unpkg.com/htmx.org@1.9.6" integrity="sha384-FhXw7b6AlE/jyjlZH5iHa/tTe9EpJ1Y55RjcgPbjeWMskSxZt1v9qkxLJWNJaGni" crossorigin="anonymous"></script> {% endblock %} {% macro renderBlogList() %} {% set page = data.query.page | default(1) | int %} {% for piece in data.pieces %} <div class="bg-preview-card"> <div class="bg-preview-date"> {{ __t('aposBlog:releasedOn') }} {{ piece.publishedAt | date('MMMM D, YYYY') }} </div> <div class="bg-preview-title"> <a href="{{ piece._url }}">{{ piece.title }}</a> </div> </div> {% endfor %} <div class="load-more-div"> {% if page != data.totalPages %} <button hx-get="/blog?page={{page + 1}}&year={{data.query.year}}&showOnlyList=1&aposRefresh=1" hx-target=".load-more-div" hx-swap="outerHTML" > Load More </button> {% endif %} </div> {% endmacro %} {% block main %} {% if data.query.showOnlyList != "1" %} <div class="bg-container"> <h1 class="bg-h1">{{ data.page.title }}</h1> <h3>{{ __t('aposBlog:filters') }}</h3> {% render filters.render({ filters: data.piecesFilters, query: data.query, url: data.page._url }) %} <h3>{{ __t('aposBlog:pluralLabel') }}</h3> {{ renderBlogList() }} </div> {% else %} {{ renderBlogList() }} {% endif %} {% endblock %} Note that the pagination element has been removed by the template. You no longer need it. Style the “Load More” button in /modules/asset/ui/src/scss/_blog.scss, and you are ready to test it. This is how your new http://localhost:3000/blog page behaves:
If you inspect the “Network” section of the browser's DevTools, you will notice that the “Load More” button triggers the following AJAX call:
htmx dev tools
This will return the HTML containing the new blog post cards to add to the page. Congrats! You just used HTMX to add a click-to-load feature to your blog. Note: You can find the entire code of this example in the htmx-load-more branch of the GitHub repository supporting the article.

 Using HTMX to Implement Infinite Scrolling

Now that you have seen how to implement a “Load More” button with HTMX, achieving infinite scrolling is easy. All you have to do is change the renderBlogList() function as follows: {% macro renderBlogList() %} {% set page = data.query.page | default(1) | int %} {% for piece in data.pieces %} <div class="bg-preview-card" {% if loop.last %} hx-get="/blog?page={{page + 1}}&year={{data.query.year}}&showOnlyList=1&aposRefresh=1" hx-trigger="revealed" hx-swap="afterend" {% endif %} > <div class="bg-preview-date"> {{ __t('aposBlog:releasedOn') }} {{ piece.publishedAt | date('MMMM D, YYYY') }} </div> <div class="bg-preview-title"> <a href="{{ piece._url }}">{{ piece.title }}</a> </div> </div> {% endfor %} {% endmacro %} The revealed HTMX event triggers when an element is scrolled into the viewport. By adding it to the last blog post card, you can implement infinite scroll loading behavior:
Awesome! Focus on the scrollbar to notice that the page adds dynamic content as the user scrolls down. Note: You can find the complete code of this example in the htmx-infinite-scrolling branch.

 Achieving Live Content Filtering Through HTMX

The goal here is to use HTMX to dynamically update the content of the page when clicking on a year filter button. In this case, you do not have to update the blog post list, but replace it entirely. Also, you need to override the HTML section that contains the filters to ensure that the correct button is enabled. First, update filters.html to introduce the HTMX logic: <!-- /modules/@apostrophecms/blog-page/views/filters.html --> {%- macro here(url, changes) -%} {{ url | build({ year: data.query.year }, { excludeContainer: 1, aposRefresh: 1 }, changes) }} {%- endmacro -%} {% fragment render(data) %} <ul class="bg-filter-list"> {% for year in data.filters.year %} <li> <button class="{{ 'is-active' if data.query.year == year.value }}" hx-get="{{ here(data.url, { year: year.value })}}" hx-target=".blog-page" hx-swap="outerHTML" > {{ __t(year.label) }} </button> </li> {% endfor %} </ul> {% endfragment %} Note that the year filter elements are no longer links, but buttons that target a specific endpoint via HTMX. In particular, here() has been updated to produce the URL required to dynamically retrieve the desired HTML content. Keep in mind that build() accepts as many query parameter objects as you need. The excludeContainer query parameter will control the rendering logic in the index.html file as below: <!-- /modules/@apostrophecms/blog-page/views/filters.html --> {% extends data.outerLayout %} {% import "filters.html" as filters %} {% import "@apostrophecms/pager:macros.html" as pager with context %} {% block title %}{{ data.page.title }} {% endblock %} {% block extraHead %} <script src="https://unpkg.com/htmx.org@1.9.6" integrity="sha384-FhXw7b6AlE/jyjlZH5iHa/tTe9EpJ1Y55RjcgPbjeWMskSxZt1v9qkxLJWNJaGni" crossorigin="anonymous"></script> {% endblock %} {% block main %} {% if data.query.excludeContainer != "1" %} <div class="bg-container"> <h1 class="bg-h1">{{ data.page.title }}</h1> {% endif %} <div class="blog-page"> <h3>{{ __t('aposBlog:filters') }}</h3> {% render filters.render({ filters: data.piecesFilters, query: data.query, url: data.page._url }) %} <h3>{{ __t('aposBlog:pluralLabel') }}</h3> {% for piece in data.pieces %} <div class="bg-preview-card"> <div class="bg-preview-date"> {{ __t('aposBlog:releasedOn') }} {{ piece.publishedAt | date('MMMM D, YYYY') }} </div> <div class="bg-preview-title"> <a href="{{ piece._url }}">{{ piece.title }}</a> </div> </div> {% endfor %} <div class="pagination"> {{ pager.render({ page: data.currentPage, total: data.totalPages }, data.url | build({ excludeContainer: null })) }} </div> </div> {% if data.query.excludeContainer != "1" %} </div> {% endif %} {% endblock %} The home page of the blog will now have real-time filtering capabilities: Awesome! You have just learned how HTMX simplifies the integration of dynamic interactions into an existing frontend application. The next step is to add a loader through the hx-indicator attribute. Check out the docs to see all the other cool features HTMX has to offer! Note: You can find the entire code of the example in the htmx-content-filtering branch.

Htmx Reference


Core Attribute Reference
Additional Attribute Reference
CSS Class Reference
HTTP Header Reference
 Request Headers Reference
 Response Headers Reference
Event Reference
JavaScript API Reference
Configuration Reference

Core Attribute Reference

  The most common attributes when using htmx. hx-get issues a GET to the specified URL hx-post issues a POST to the specified URL hx-on* handle events with inline scripts on elements hx-push-url push a URL into the browser location bar to create history hx-select select content to swap in from a response hx-select-oob select content to swap in from a response, somewhere other than the target (out of band) hx-swap controls how content will swap in (outerHTML, beforeend, afterend, …) hx-swap-oob mark element to swap in from a response (out of band) hx-target specifies the target element to be swapped hx-trigger specifies the event that triggers the request hx-vals add values to submit with the request (JSON format)

Additional Attribute Reference

  All other attributes available in htmx. hx-boost add progressive enhancement for links and forms hx-confirm shows a confirm() dialog before issuing a request hx-delete issues a DELETE to the specified URL hx-disable disables htmx processing for the given node and any children nodes hx-disabled-elt adds the disabled attribute to the specified elements while a request is in flight hx-disinherit control and disable automatic attribute inheritance for child nodes hx-encoding changes the request encoding type hx-ext extensions to use for this element hx-headers adds to the headers that will be submitted with the request hx-history prevent sensitive data being saved to the history cache hx-history-elt the element to snapshot and restore during history navigation hx-include include additional data in requests hx-indicator the element to put the htmx-request class on during the request hx-inherit control and enable automatic attribute inheritance for child nodes if it has been disabled by default hx-params filters the parameters that will be submitted with a request hx-patch issues a PATCH to the specified URL hx-preserve specifies elements to keep unchanged between requests hx-prompt shows a prompt() before submitting a request hx-put issues a PUT to the specified URL hx-replace-url replace the URL in the browser location bar hx-request configures various aspects of the request hx-sync control how requests made by different elements are synchronized hx-validate force elements to validate themselves before a request hx-vars adds values dynamically to the parameters to submit with the request (deprecated, please use hx-vals)

CSS Class Reference

htmx-added Applied to a new piece of content before it is swapped, removed after it is settled. htmx-indicator A dynamically generated class that will toggle visible (opacity:1) when a htmx-request class is present htmx-request Applied to either the element or the element specified with hx-indicator while a request is ongoing htmx-settling Applied to a target after content is swapped, removed after it is settled. The duration can be modified via hx-swap. htmx-swapping Applied to a target before any content is swapped, removed after it is swapped. The duration can be modified via hx-swap.

HTTP Header Reference

 Request Headers Reference

HX-Boosted indicates that the request is via an element using hx-boost HX-Current-URL the current URL of the browser HX-History-Restore-Request “true” if the request is for history restoration after a miss in the local history cache HX-Prompt the user response to an hx-prompt HX-Request always “true” HX-Target the id of the target element if it exists HX-Trigger-Name the name of the triggered element if it exists HX-Trigger the id of the triggered element if it exists

 Response Headers Reference

HX-Location allows you to do a client-side redirect that does not do a full page reload HX-Push-Url pushes a new url into the history stack HX-Redirect can be used to do a client-side redirect to a new location HX-Refresh if set to “true” the client-side will do a full refresh of the page HX-Replace-Url replaces the current URL in the location bar HX-Reswap allows you to specify how the response will be swapped. See hx-swap for possible values HX-Retarget a CSS selector that updates the target of the content update to a different element on the page HX-Reselect a CSS selector that allows you to choose which part of the response is used to be swapped in. Overrides an existing hx-select on the triggering element HX-Trigger allows you to trigger client-side events HX-Trigger-After-Settle allows you to trigger client-side events after the settle step HX-Trigger-After-Swap allows you to trigger client-side events after the swap step

Event Reference

htmx:abort send this event to an element to abort a request htmx:afterOnLoad triggered after an AJAX request has completed processing a successful response htmx:afterProcessNode triggered after htmx has initialized a node htmx:afterRequest triggered after an AJAX request has completed htmx:afterSettle triggered after the DOM has settled htmx:afterSwap triggered after new content has been swapped in htmx:beforeCleanupElement triggered before htmx disables an element or removes it from the DOM htmx:beforeOnLoad triggered before any response processing occurs htmx:beforeProcessNode triggered before htmx initializes a node htmx:beforeRequest triggered before an AJAX request is made htmx:beforeSwap triggered before a swap is done, allows you to configure the swap htmx:beforeSend triggered just before an ajax request is sent htmx:configRequest triggered before the request, allows you to customize parameters, headers htmx:confirm triggered after a trigger occurs on an element, allows you to cancel (or delay) issuing the AJAX request htmx:historyCacheError triggered on an error during cache writing htmx:historyCacheMiss triggered on a cache miss in the history subsystem htmx:historyCacheMissError triggered on a unsuccessful remote retrieval htmx:historyCacheMissLoad triggered on a successful remote retrieval htmx:historyRestore triggered when htmx handles a history restoration action htmx:beforeHistorySave triggered before content is saved to the history cache htmx:load triggered when new content is added to the DOM htmx:noSSESourceError triggered when an element refers to a SSE event in its trigger, but no parent SSE source has been defined htmx:onLoadError triggered when an exception occurs during the onLoad handling in htmx htmx:oobAfterSwap triggered after an out of band element as been swapped in htmx:oobBeforeSwap triggered before an out of band element swap is done, allows you to configure the swap htmx:oobErrorNoTarget triggered when an out of band element does not have a matching ID in the current DOM htmx:prompt triggered after a prompt is shown htmx:pushedIntoHistory triggered after an url is pushed into history htmx:responseError triggered when an HTTP response error (non-200 or 300 response code) occurs htmx:sendError triggered when a network error prevents an HTTP request from happening htmx:sseError triggered when an error occurs with a SSE source htmx:sseOpen triggered when a SSE source is opened htmx:swapError triggered when an error occurs during the swap phase htmx:targetError triggered when an invalid target is specified htmx:timeout triggered when a request timeout occurs htmx:validation:validate triggered before an element is validated htmx:validation:failed triggered when an element fails validation htmx:validation:halted triggered when a request is halted due to validation errors htmx:xhr:abort triggered when an ajax request aborts htmx:xhr:loadend triggered when an ajax request ends htmx:xhr:loadstart triggered when an ajax request starts htmx:xhr:progress triggered periodically during an ajax request that supports progress events

JavaScript API Reference

htmx.addClass() Adds a class to the given element htmx.ajax() Issues an htmx-style ajax request htmx.closest() Finds the closest parent to the given element matching the selector htmx.config A property that holds the current htmx config object htmx.createEventSource A property holding the function to create SSE EventSource objects for htmx htmx.createWebSocket A property holding the function to create WebSocket objects for htmx htmx.defineExtension() Defines an htmx extension htmx.find() Finds a single element matching the selector htmx.findAll() htmx.findAll(elt, selector) Finds all elements matching a given selector htmx.logAll() Installs a logger that will log all htmx events htmx.logger A property set to the current logger (default is null) htmx.off() Removes an event listener from the given element htmx.on() Creates an event listener on the given element, returning it htmx.onLoad() Adds a callback handler for the htmx:load event htmx.parseInterval() Parses an interval declaration into a millisecond value htmx.process() Processes the given element and its children, hooking up any htmx behavior htmx.remove() Removes the given element htmx.removeClass() Removes a class from the given element htmx.removeExtension() Removes an htmx extension htmx.swap() Performs swapping (and settling) of HTML content htmx.takeClass() Takes a class from other elements for the given element htmx.toggleClass() Toggles a class from the given element htmx.trigger() Triggers an event on an element htmx.values() Returns the input values associated with the given element

Configuration Reference

  Htmx has some configuration options that can be accessed either programmatically or declaratively. They are listed below: htmx.config.historyEnabled defaults to true, really only useful for testing htmx.config.historyCacheSize defaults to 10 htmx.config.refreshOnHistoryMiss defaults to false, if set to true htmx will issue a full page refresh on history misses rather than use an AJAX request htmx.config.defaultSwapStyle defaults to innerHTML htmx.config.defaultSwapDelay defaults to 0 htmx.config.defaultSettleDelay defaults to 20 htmx.config.includeIndicatorStyles defaults to true (determines if the indicator styles are loaded) htmx.config.indicatorClass defaults to htmx-indicator htmx.config.requestClass defaults to htmx-request htmx.config.addedClass defaults to htmx-added htmx.config.settlingClass defaults to htmx-settling htmx.config.swappingClass defaults to htmx-swapping htmx.config.allowEval defaults to true, can be used to disable htmx’s use of eval for certain features (e.g. trigger filters) htmx.config.allowScriptTags defaults to true, determines if htmx will process script tags found in new content htmx.config.inlineScriptNonce defaults to '', meaning that no nonce will be added to inline scripts htmx.config.inlineSlyeNonce defaults to '', meaning that no nonce will be added to inline styles htmx.config.attributesToSettle defaults to ["class", "style", "width", "height"], the attributes to settle during the settling phase htmx.config.wsReconnectDelay defaults to full-jitter htmx.config.wsBinaryType defaults to blob, the the type of binary data being received over the WebSocket connection htmx.config.disableSelector defaults to [hx-disable], [data-hx-disable], htmx will not process elements with this attribute on it or a parent htmx.config.withCredentials defaults to false, allow cross-site Access-Control requests using credentials such as cookies, authorization headers or TLS client certificates htmx.config.timeout defaults to 0, the number of milliseconds a request can take before automatically being terminated htmx.config.scrollBehavior defaults to ‘instant’, the behavior for a boosted link on page transitions. The allowed values are auto, instant and smooth. Instant will scroll instantly in a single jump, smooth will scroll smoothly, while auto will behave like a vanilla link. htmx.config.defaultFocusScroll if the focused element should be scrolled into view, defaults to false and can be overridden using the focus-scroll swap modifier. htmx.config.getCacheBusterParam defaults to false, if set to true htmx will append the target element to the GET request in the format org.htmx.cache-buster=targetElementId htmx.config.globalViewTransitions if set to true, htmx will use the View Transition API when swapping in new content. htmx.config.methodsThatUseUrlParams defaults to ["get"], htmx will format requests with these methods by encoding their parameters in the URL, not the request body htmx.config.selfRequestsOnly defaults to true, whether to only allow AJAX requests to the same domain as the current document htmx.config.ignoreTitle defaults to false, if set to true htmx will not update the title of the document when a title tag is found in new content htmx.config.scrollIntoViewOnBoost defaults to true, whether or not the target of a boosted element is scrolled into the viewport. If hx-target is omitted on a boosted element, the target defaults to body, causing the page to scroll to the top. htmx.config.triggerSpecsCache defaults to null, the cache to store evaluated trigger specifications into, improving parsing performance at the cost of more memory usage. You may define a simple object to use a never-clearing cache, or implement your own system using a proxy object htmx.config.allowNestedOobSwaps defaults to true, whether to process OOB swaps on elements that are nested within the main response element. See Nested OOB Swaps. You can set them directly in javascript, or you can use a meta tag: <meta name="htmx-config" content='{"defaultSwapStyle":"outerHTML"}'>

hx-boost

The hx-boost attribute allows you to “boost” normal anchors and form tags to use AJAX instead. This has the nice fallback that, if the user does not have javascript enabled, the site will continue to work. For anchor tags, clicking on the anchor will issue a GET request to the url specified in the href and will push the url so that a history entry is created. The target is the <body> tag, and the innerHTML swap strategy is used by default. All of these can be modified by using the appropriate attributes, except the click trigger. For forms the request will be converted into a GET or POST, based on the method in the method attribute and will be triggered by a submit. Again, the target will be the body of the page, and the innerHTML swap will be used. The url will not be pushed, however, and no history entry will be created. (You can use the hx-push-url attribute if you want the url to be pushed.) Here is an example of some boosted links: <div hx-boost="true"> <a href="/page1">Go To Page 1</a> <a href="/page2">Go To Page 2</a> </div> These links will issue an ajax GET request to the respective URLs and replace the body’s inner content with it. Here is an example of a boosted form: <form hx-boost="true" action="/example" method="post"> <input name="email" type="email" placeholder="Enter email..."> <button>Submit</button> </form> This form will issue an ajax POST to the given URL and replace the body’s inner content with it.

 Notes

hx-boost is inherited and can be placed on a parent element Only links that are to the same domain and that are not local anchors will be boosted All requests are done via AJAX, so keep that in mind when doing things like redirects To find out if the request results from a boosted anchor or form, look for HX-Boosted in the request header Selectively disable boost on child elements with hx-boost="false" Disable the replacement of elements via boost, and their children, with hx-preserve="true"

hx-confirm

The hx-confirm attribute allows you to confirm an action before issuing a request. This can be useful in cases where the action is destructive and you want to ensure that the user really wants to do it. Here is an example: <button hx-delete="/account" hx-confirm="Are you sure you wish to delete your account?"> Delete My Account </button>

 Event details

The event triggered by hx-confirm contains additional properties in its detail: triggeringEvent: the event that triggered the original request issueRequest(skipConfirmation=false): a callback which can be used to confirm the AJAX request question: the value of the hx-confirm attribute on the HTML element

 Notes

hx-confirm is inherited and can be placed on a parent element hx-confirm uses the browser’s window.confirm by default. You can customize this behavior as shown in this example. a boolean skipConfirmation can be passed to the issueRequest callback; if true (defaults to false), the window.confirm will not be called and the AJAX request is issued directly

hx-delete

The hx-delete attribute will cause an element to issue a DELETE to the specified URL and swap the HTML into the DOM using a swap strategy: <button hx-delete="/account" hx-target="body"> Delete Your Account </button> This example will cause the button to issue a DELETE to /account and swap the returned HTML into the innerHTML of the body.

 Notes

hx-delete is not inherited You can control the target of the swap using the hx-target attribute You can control the swap strategy by using the hx-swap attribute You can control what event triggers the request with the hx-trigger attribute You can control the data submitted with the request in various ways, documented here: Parameters To remove the element following a successful DELETE, return a 200 status code with an empty body; if the server responds with a 204, no swap takes place, documented here: Requests & Responses

hx-disable

The hx-disable attribute will disable htmx processing for a given element and all its children. This can be useful as a backup for HTML escaping, when you include user generated content in your site, and you want to prevent malicious scripting attacks. The value of the tag is ignored, and it cannot be reversed by any content beneath it.

 Notes

hx-disable is inherited

hx-disabled-elt

The hx-disabled-elt attribute allows you to specify elements that will have the disabled attribute added to them for the duration of the request. The value of this attribute can be: A CSS query selector of the element to disable. this to disable the element itself closest <CSS selector> which will find the closest ancestor element or itself, that matches the given CSS selector (e.g. closest fieldset will disable the closest to the element fieldset). find <CSS selector> which will find the first child descendant element that matches the given CSS selector next which resolves to element.nextElementSibling next <CSS selector> which will scan the DOM forward for the first element that matches the given CSS selector (e.g. next button will disable the closest following sibling button element) previous which resolves to element.previousElementSibling previous <CSS selector> which will scan the DOM backwards for the first element that matches the given CSS selector. (e.g previous input will disable the closest previous sibling input element) Here is an example with a button that will disable itself during a request: <button hx-post="/example" hx-disabled-elt="this"> Post It! </button> When a request is in flight, this will cause the button to be marked with the disabled attribute, which will prevent further clicks from occurring. The hx-disabled-elt attribute also supports specifying multiple CSS selectors separated by commas to disable multiple elements during the request. Here is an example that disables buttons and text input fields of a particular form during the request: <form hx-post="/example" hx-disabled-elt="find input[type='text'], find button"> <input type="text" placeholder="Type here..."> <button type="submit">Send</button> </form>

 Notes

hx-disabled-elt is inherited and can be placed on a parent element

hx-disinherit

The default behavior for htmx is to “inherit” many attributes automatically: that is, an attribute such as hx-target may be placed on a parent element, and all child elements will inherit that target. The hx-disinherit attribute allows you to control this automatic attribute inheritance. An example scenario is to allow you to place an hx-boost on the body element of a page, but overriding that behavior in a specific part of the page to allow for more specific behaviors. htmx evaluates attribute inheritance as follows: when hx-disinherit is set on a parent node hx-disinherit="*" all attribute inheritance for this element will be disabled hx-disinherit="hx-select hx-get hx-target" disable inheritance for only one or multiple specified attributes <div hx-boost="true" hx-select="#content" hx-target="#content" hx-disinherit="*"> <a href="/page1">Go To Page 1</a> <!-- boosted with the attribute settings above --> <a href="/page2" hx-boost="unset">Go To Page 1</a> <!-- not boosted --> <button hx-get="/test" hx-target="this"></button> <!-- hx-select is not inherited --> </div> <div hx-boost="true" hx-select="#content" hx-target="#content" hx-disinherit="hx-target"> <!-- hx-select is automatically set to parent's value; hx-target is not inherited --> <button hx-get="/test"></button> </div> <div hx-select="#content"> <div hx-boost="true" hx-target="#content" hx-disinherit="hx-select"> <!-- hx-target is automatically inherited from parent's value --> <!-- hx-select is not inherited, because the direct parent does disables inheritance, despite not specifying hx-select itself --> <button hx-get="/test"></button> </div> </div>

 Notes

Read more about Attribute Inheritance

hx-encoding

The hx-encoding attribute allows you to switch the request encoding from the usual application/x-www-form-urlencoded encoding to multipart/form-data, usually to support file uploads in an ajax request. The value of this attribute should be multipart/form-data. The hx-encoding tag may be placed on parent elements.

 Notes

hx-encoding is inherited and can be placed on a parent element

hx-ext

The hx-ext attribute enables an htmx extension for an element and all its children. The value can be a single extension name or a comma separated list of extensions to apply. The hx-ext tag may be placed on parent elements if you want a plugin to apply to an entire swath of the DOM, and on the body tag for it to apply to all htmx requests.

 Notes

hx-ext is both inherited and merged with parent elements, so you can specify extensions on any element in the DOM hierarchy and it will apply to all child elements. You can ignore an extension that is defined by a parent node using hx-ext="ignore:extensionName" <div hx-ext="example"> "Example" extension is used in this part of the tree... <div hx-ext="ignore:example"> ... but it will not be used in this part. </div> </div>

hx-get

The hx-get attribute will cause an element to issue a GET to the specified URL and swap the HTML into the DOM using a swap strategy: <div hx-get="/example">Get Some HTML</div> This example will cause the div to issue a GET to /example and swap the returned HTML into the innerHTML of the div.

  Notes

hx-get is not inherited By default hx-get does not include any parameters. You can use the hx-params attribute to change this You can control the target of the swap using the hx-target attribute You can control the swap strategy by using the hx-swap attribute You can control what event triggers the request with the hx-trigger attribute You can control the data submitted with the request in various ways, documented here: Parameters An empty hx-get:"" will make a get request to the current url and will swap the current HTML page

hx-headers

The hx-headers attribute allows you to add to the headers that will be submitted with an AJAX request. By default, the value of this attribute is a list of name-expression values in JSON (JavaScript Object Notation) format. If you wish for hx-headers to evaluate the values given, you can prefix the values with javascript: or js:. <div hx-get="/example" hx-headers='{"myHeader": "My Value"}'>Get Some HTML, Including A Custom Header in the Request</div>

 Security Considerations

By default, the value of hx-headers must be valid JSON. It is not dynamically computed. If you use the javascript: prefix, be aware that you are introducing security considerations, especially when dealing with user input such as query strings or user-generated content, which could introduce a Cross-Site Scripting (XSS) vulnerability.

 Notes

hx-headers is inherited and can be placed on a parent element. A child declaration of a header overrides a parent declaration.

hx-history-elt

The hx-history-elt attribute allows you to specify the element that will be used to snapshot and restore page state during navigation. By default, the body tag is used. This is typically good enough for most setups, but you may want to narrow it down to a child element. Just make sure that the element is always visible in your application, or htmx will not be able to restore history navigation properly. Here is an example: <html> <body> <div id="content" hx-history-elt> ... </div> </body> </html>

 Notes

hx-history-elt is not inherited In most cases we don’t recommend narrowing the history snapshot

hx-history

Set the hx-history attribute to false on any element in the current document, or any html fragment loaded into the current document by htmx, to prevent sensitive data being saved to the localStorage cache when htmx takes a snapshot of the page state. History navigation will work as expected, but on restoration the URL will be requested from the server instead of the history cache. Here is an example: <html> <body> <div hx-history="false"> ... </div> </body> </html>

 Notes

hx-history="false" can be present anywhere in the document to embargo the current page state from the history cache (i.e. even outside the element specified for the history snapshot hx-history-elt).

hx-include

The hx-include attribute allows you to include additional element values in an AJAX request. The value of this attribute can be: A CSS query selector of the elements to include. this which will include the descendants of the element. closest <CSS selector> which will find the closest ancestor element or itself, that matches the given CSS selector (e.g. closest tr will target the closest table row to the element). find <CSS selector> which will find the first child descendant element that matches the given CSS selector. next <CSS selector> which will scan the DOM forward for the first element that matches the given CSS selector. (e.g. next .error will target the closest following sibling element with error class) previous <CSS selector> which will scan the DOM backwards for the first element that matches the given CSS selector. (e.g previous .error will target the closest previous sibling with error class) Here is an example that includes a separate input value: <div> <button hx-post="/register" hx-include="[name='email']"> Register! </button> Enter email: <input name="email" type="email"/> </div> This is a little contrived as you would typically enclose both of these elements in a form and submit the value automatically, but it demonstrates the concept. Note that if you include a non-input element, all input elements enclosed in that element will be included.

 Notes

hx-include is inherited and can be placed on a parent element While hx-include is inherited, it is evaluated from the element triggering the request. It is easy to get confused when working with the extended selectors such as find and closest.<div hx-include="find input"> <button hx-post="/register"> Register! </button> Enter email: <input name="email" type="email"/> </div> In the above example, when clicking on the button, the find input selector is resolved from the button itself, which does not return any element here, since the button doesn’t have any input child, thus in this case, raises an error. A standard CSS selector resolves to document.querySelectorAll and will include multiple elements, while the extended selectors such as find or next only return a single element at most to include

hx-indicator

The hx-indicator attribute allows you to specify the element that will have the htmx-request class added to it for the duration of the request. This can be used to show spinners or progress indicators while the request is in flight. The value of this attribute is a CSS query selector of the element or elements to apply the class to, or the keyword closest, followed by a CSS selector, which will find the closest ancestor element or itself, that matches the given CSS selector (e.g. closest tr); Here is an example with a spinner adjacent to the button: <div> <button hx-post="/example" hx-indicator="#spinner"> Post It! </button> <img id="spinner" class="htmx-indicator" src="/img/bars.svg"/> </div> When a request is in flight, this will cause the htmx-request class to be added to the #spinner image. The image also has the htmx-indicator class on it, which defines an opacity transition that will show the spinner: .htmx-indicator{ opacity:0; transition: opacity 500ms ease-in; } .htmx-request .htmx-indicator{ opacity:1 } .htmx-request.htmx-indicator{ opacity:1 } If you would prefer a different effect for showing the spinner you could define and use your own indicator CSS. Here is an example that uses display rather than opacity (Note that we use my-indicator instead of htmx-indicator): .my-indicator{ display:none; } .htmx-request .my-indicator{ display:inline; } .htmx-request.my-indicator{ display:inline; } Note that the target of the hx-indicator selector need not be the exact element that you want to show: it can be any element in the parent hierarchy of the indicator. Finally, note that the htmx-request class by default is added to the element causing the request, so you can place an indicator inside of that element and not need to explicitly call it out with the hx-indicator attribute: <button hx-post="/example"> Post It! <img class="htmx-indicator" src="/img/bars.svg"/> </button>

 Demo

This simulates what a spinner might look like in that situation:

 Notes

hx-indicator is inherited and can be placed on a parent element In the absence of an explicit indicator, the htmx-request class will be added to the element triggering the request If you want to use your own CSS but still use htmx-indicator as class name, then you need to disable includeIndicatorStyles. See Configuring htmx. The easiest way is to add this to the <head> of your HTML: <meta name="htmx-config" content='{"includeIndicatorStyles": false}'>

hx-inherit

The default behavior for htmx is to “inherit” many attributes automatically: that is, an attribute such as hx-target may be placed on a parent element, and all child elements will inherit that target. Some people do not like this feature and instead prefer to explicitly specify inheritance for attributes. To support this mode of development, htmx offers the htmx.config.disableInheritance setting, which can be set to false to prevent inheritance from being the default behavior for any of the htmx attributes. The hx-inherit attribute allows you to control the inheritance of attributes manually. htmx evaluates attribute inheritance as follows: when hx-inherit is set on a parent node inherit="*" all attribute inheritance for this element will be enabled hx-inherit="hx-select hx-get hx-target" enable inheritance for only one or multiple specified attributes Here is an example of a div that shares an hx-target attribute for a set of anchor tags when htmx.config.disableInheritance is set to false: <div hx-target="#tab-container" hx-inherit="hx-target"> <a hx-boost="true" href="/tab1">Tab 1</a> <a hx-boost="true" href="/tab2">Tab 2</a> <a hx-boost="true" href="/tab3">Tab 3</a> </div>

 Notes

Read more about Attribute Inheritance

hx-on

The hx-on* attributes allow you to embed scripts inline to respond to events directly on an element; similar to the onevent properties found in HTML, such as onClick. The hx-on* attributes improve upon onevent by enabling the handling of any arbitrary JavaScript event, for enhanced Locality of Behaviour (LoB) even when dealing with non-standard DOM events. For example, these attributes allow you to handle htmx events. With hx-on attributes, you specify the event name as part of the attribute name, after a colon. So, for example, if you want to respond to a click event, you would use the attribute hx-on:click: <div hx-on:click="alert('Clicked!')">Click</div> Note that this syntax can be used to capture all htmx events, as well as most other custom events, in addition to the standard DOM events. One gotcha to note is that DOM attributes do not preserve case. This means, unfortunately, an attribute like hx-on:htmx:beforeRequest will not work, because the DOM lowercases the attribute names. Fortunately, htmx supports both camel case event names and also kebab-case event names, so you can use hx-on:htmx:before-request instead. In order to make writing htmx-based event handlers a little easier, you can use the shorthand double-colon hx-on:: for htmx events, and omit the “htmx” part: <!-- These two are equivalent --> <button hx-get="/info" hx-on:htmx:before-request="alert('Making a request!')"> Get Info! </button> <button hx-get="/info" hx-on::before-request="alert('Making a request!')"> Get Info! </button> If you wish to handle multiple different events, you can simply add multiple attributes to an element: <button hx-get="/info" hx-on::before-request="alert('Making a request!')" hx-on::after-request="alert('Done making a request!')"> Get Info! </button> Finally, in order to make this feature compatible with some templating languages (e.g. JSX) that do not like having a colon (:) in HTML attributes, you may use dashes in the place of colons for both the long form and the shorthand form: <!-- These two are equivalent --> <button hx-get="/info" hx-on-htmx-before-request="alert('Making a request!')"> Get Info! </button> <button hx-get="/info" hx-on--before-request="alert('Making a request!')"> Get Info! </button>

  hx-on (deprecated)

The value is an event name, followed by a colon :, followed by the script: <button hx-get="/info" hx-on="htmx:beforeRequest: alert('Making a request!')"> Get Info! </button> Multiple handlers can be defined by putting them on new lines: <button hx-get="/info" hx-on="htmx:beforeRequest: alert('Making a request!') htmx:afterRequest: alert('Done making a request!')"> Get Info! </button>

  Symbols

Like onevent, two symbols are made available to event handler scripts: this - The element on which the hx-on attribute is defined event - The event that triggered the handler

  Notes

hx-on is not inherited, however due to event bubbling, hx-on attributes on parent elements will typically be triggered by events on child elements hx-on:* and hx-on cannot be used together on the same element; if hx-on:* is present, the value of an hx-on attribute on the same element will be ignored. The two forms can be mixed in the same document, however.

hx-params

The hx-params attribute allows you to filter the parameters that will be submitted with an AJAX request. The possible values of this attribute are: * - Include all parameters (default) none - Include no parameters not <param-list> - Include all except the comma separated list of parameter names <param-list> - Include all the comma separated list of parameter names <div hx-get="/example" hx-params="*">Get Some HTML, Including Params</div> This div will include all the parameters that a POST would, but they will be URL encoded and included in the URL, as per usual with a GET.

 Notes

hx-params is inherited and can be placed on a parent element

hx-patch

The hx-patch attribute will cause an element to issue a PATCH to the specified URL and swap the HTML into the DOM using a swap strategy: <button hx-patch="/account" hx-target="body"> Patch Your Account </button> This example will cause the button to issue a PATCH to /account and swap the returned HTML into the innerHTML of the body.

 Notes

hx-patch is not inherited You can control the target of the swap using the hx-target attribute You can control the swap strategy by using the hx-swap attribute You can control what event triggers the request with the hx-trigger attribute You can control the data submitted with the request in various ways, documented here: Parameters

hx-post

The hx-post attribute will cause an element to issue a POST to the specified URL and swap the HTML into the DOM using a swap strategy: <button hx-post="/account/enable" hx-target="body"> Enable Your Account </button> This example will cause the button to issue a POST to /account/enable and swap the returned HTML into the innerHTML of the body.

 Notes

hx-post is not inherited You can control the target of the swap using the hx-target attribute You can control the swap strategy by using the hx-swap attribute You can control what event triggers the request with the hx-trigger attribute You can control the data submitted with the request in various ways, documented here: Parameters

hx-preserve

The hx-preserve attribute allows you to keep an element unchanged during HTML replacement. Elements with hx-preserve set are preserved by id when htmx updates any ancestor element. You must set an unchanging id on elements for hx-preserve to work. The response requires an element with the same id, but its type and other attributes are ignored. Note that some elements cannot unfortunately be preserved properly, such as <input type="text"> (focus and caret position are lost), iframes or certain types of videos. To tackle some of these cases we recommend the morphdom extension, which does a more elaborate DOM reconciliation.

 Notes

hx-preserve is not inherited

hx-prompt

The hx-prompt attribute allows you to show a prompt before issuing a request. The value of the prompt will be included in the request in the HX-Prompt header. Here is an example: <button hx-delete="/account" hx-prompt="Enter your account name to confirm deletion"> Delete My Account </button>

 Notes

hx-prompt is inherited and can be placed on a parent element

hx-push-url

The hx-push-url attribute allows you to push a URL into the browser location history. This creates a new history entry, allowing navigation with the browser’s back and forward buttons. htmx snapshots the current DOM and saves it into its history cache, and restores from this cache on navigation. The possible values of this attribute are: true, which pushes the fetched URL into history. false, which disables pushing the fetched URL if it would otherwise be pushed due to inheritance or hx-boost. A URL to be pushed into the location bar. This may be relative or absolute, as per history.pushState(). Here is an example: <div hx-get="/account" hx-push-url="true"> Go to My Account </div> This will cause htmx to snapshot the current DOM to localStorage and push the URL `/account’ into the browser location bar. Another example: <div hx-get="/account" hx-push-url="/account/home"> Go to My Account </div> This will push the URL `/account/home’ into the location history.

 Notes

hx-push-url is inherited and can be placed on a parent element The HX-Push-Url response header has similar behavior and can override this attribute. The hx-history-elt attribute allows changing which element is saved in the history cache.

hx-put

The hx-put attribute will cause an element to issue a PUT to the specified URL and swap the HTML into the DOM using a swap strategy: <button hx-put="/account" hx-target="body"> Put Money In Your Account </button> This example will cause the button to issue a PUT to /account and swap the returned HTML into the innerHTML of the body.

 Notes

hx-put is not inherited You can control the target of the swap using the hx-target attribute You can control the swap strategy by using the hx-swap attribute You can control what event triggers the request with the hx-trigger attribute You can control the data submitted with the request in various ways, documented here: Parameters

hx-replace-url

The hx-replace-url attribute allows you to replace the current url of the browser location history. The possible values of this attribute are: true, which replaces the fetched URL in the browser navigation bar. false, which disables replacing the fetched URL if it would otherwise be replaced due to inheritance. A URL to be replaced into the location bar. This may be relative or absolute, as per history.replaceState(). Here is an example: <div hx-get="/account" hx-replace-url="true"> Go to My Account </div> This will cause htmx to snapshot the current DOM to localStorage and replace the URL `/account’ in the browser location bar. Another example: <div hx-get="/account" hx-replace-url="/account/home"> Go to My Account </div> This will replace the URL `/account/home’ in the browser location bar.

 Notes

hx-replace-url is inherited and can be placed on a parent element The HX-Replace-Url response header has similar behavior and can override this attribute. The hx-history-elt attribute allows changing which element is saved in the history cache. The hx-push-url attribute is a similar and more commonly used attribute, which creates a new history entry rather than replacing the current one.

hx-request

The hx-request attribute allows you to configure various aspects of the request via the following attributes: timeout - the timeout for the request, in milliseconds credentials - if the request will send credentials noHeaders - strips all headers from the request These attributes are set using a JSON-like syntax: <div ... hx-request='{"timeout":100}'> ... </div> You may make the values dynamically evaluated by adding the javascript: or js: prefix: <div ... hx-request='js: timeout:getTimeoutSetting() '> ... </div>

 Notes

hx-request is merge-inherited and can be placed on a parent element

hx-select-oob

The hx-select-oob attribute allows you to select content from a response to be swapped in via an out-of-band swap.
The value of this attribute is comma separated list of elements to be swapped out of band. This attribute is almost always paired with hx-select. Here is an example that selects a subset of the response content: <div> <div id="alert"></div> <button hx-get="/info" hx-select="#info-details" hx-swap="outerHTML" hx-select-oob="#alert"> Get Info! </button> </div> This button will issue a GET to /info and then select the element with the id info-details, which will replace the entire button in the DOM, and, in addition, pick out an element with the id alert in the response and swap it in for div in the DOM with the same ID. Each value in the comma separated list of values can specify any valid hx-swap strategy by separating the selector and the swap strategy with a :. For example, to prepend the alert content instead of replacing it: <div> <div id="alert"></div> <button hx-get="/info" hx-select="#info-details" hx-swap="outerHTML" hx-select-oob="#alert:afterbegin"> Get Info! </button> </div>

 Notes

hx-select-oob is inherited and can be placed on a parent element

hx-select

The hx-select attribute allows you to select the content you want swapped from a response. The value of this attribute is a CSS query selector of the element or elements to select from the response. Here is an example that selects a subset of the response content: <div> <button hx-get="/info" hx-select="#info-details" hx-swap="outerHTML"> Get Info! </button> </div> So this button will issue a GET to /info and then select the element with the id info-detail, which will replace the entire button in the DOM.

 Notes

hx-select is inherited and can be placed on a parent element

hx-swap-oob

The hx-swap-oob attribute allows you to specify that some content in a response should be swapped into the DOM somewhere other than the target, that is “Out of Band”. This allows you to piggy back updates to other element updates on a response. Consider the following response HTML: <div> ... </div> <div id="alerts" hx-swap-oob="true"> Saved! </div> The first div will be swapped into the target the usual manner. The second div, however, will be swapped in as a replacement for the element with the id alerts, and will not end up in the target. The value of the hx-swap-oob can be: true any valid hx-swap value any valid hx-swap value, followed by a colon, followed by a CSS selector If the value is true or outerHTML (which are equivalent) the element will be swapped inline. If a swap value is given, that swap strategy will be used. If a selector is given, all elements matched by that selector will be swapped. If not, the element with an ID matching the new content will be swapped.

  Troublesome Tables

Note that you can use a template tag to encapsulate types of elements that, by the HTML spec, can’t stand on their own in the DOM (<tr>, <td>, <th>, <thead>, <tbody>, <tfoot>, <colgroup>, <caption> & <col>). Here is an example with an out of band swap of a table row being encapsulated in this way: <div> ... </div> <template> <tr id="row" hx-swap-oob="true"> ... </tr> </template> Note that these template tags will be removed from the final content of the page.

 Nested OOB Swaps

By default, any element with hx-swap-oob= attribute anywhere in the response is processed for oob swap behavior, including when an element is nested within the main response element. This can be problematic when using template fragments where a fragment may be reused as a oob-swap target and also as part of a bigger fragment. When the bigger fragment is the main response the inner fragment will still be processed as an oob swap, removing it from the dom. This behavior can be changed by setting the config htmx.config.allowNestedOobSwaps to false. If this config option is false, OOB swaps are only processed when the element is adjacent to the main response element, OOB swaps elsewhere will be ignored and oob-swap-related attributes stripped.

 Notes

hx-swap-oob is not inherited

hx-swap

The hx-swap attribute allows you to specify how the response will be swapped in relative to the target of an AJAX request. If you do not specify the option, the default is htmx.config.defaultSwapStyle (innerHTML). The possible values of this attribute are: innerHTML - Replace the inner html of the target element outerHTML - Replace the entire target element with the response textContent - Replace the text content of the target element, without parsing the response as HTML beforebegin - Insert the response before the target element afterbegin - Insert the response before the first child of the target element beforeend - Insert the response after the last child of the target element afterend - Insert the response after the target element delete - Deletes the target element regardless of the response none- Does not append content from response (out of band items will still be processed). These options are based on standard DOM naming and the Element.insertAdjacentHTML specification. So in this code: <div hx-get="/example" hx-swap="afterend">Get Some HTML & Append It</div> The div will issue a request to /example and append the returned content after the div

  Modifiers

The hx-swap attributes supports modifiers for changing the behavior of the swap. They are outlined below.

Transition: transition

If you want to use the new View Transitions API when a swap occurs, you can use the transition:true option for your swap. You can also enable this feature globally by setting the htmx.config.globalViewTransitions config setting to true.

Timing: swap & settle

You can modify the amount of time that htmx will wait after receiving a response to swap the content by including a swap modifier: <!-- this will wait 1s before doing the swap after it is received --> <div hx-get="/example" hx-swap="innerHTML swap:1s">Get Some HTML & Append It</div> Similarly, you can modify the time between the swap and the settle logic by including a settle modifier: <!-- this will wait 1s before doing the swap after it is received --> <div hx-get="/example" hx-swap="innerHTML settle:1s">Get Some HTML & Append It</div> These attributes can be used to synchronize htmx with the timing of CSS transition effects.

Title: ignoreTitle

By default, htmx will update the title of the page if it finds a <title> tag in the response content. You can turn off this behavior by setting the ignoreTitle option to true.

Scrolling: scroll & show

You can also change the scrolling behavior of the target element by using the scroll and show modifiers, both of which take the values top and bottom: <!-- this fixed-height div will scroll to the bottom of the div after content is appended --> <div style="height:200px; overflow: scroll" hx-get="/example" hx-swap="beforeend scroll:bottom"> Get Some HTML & Append It & Scroll To Bottom </div> <!-- this will get some content and add it to #another-div, then ensure that the top of #another-div is visible in the viewport --> <div hx-get="/example" hx-swap="innerHTML show:top" hx-target="#another-div"> Get Some Content </div> If you wish to target a different element for scrolling or showing, you may place a CSS selector after the scroll: or show:, followed by :top or :bottom: <!-- this will get some content and swap it into the current div, then ensure that the top of #another-div is visible in the viewport --> <div hx-get="/example" hx-swap="innerHTML show:#another-div:top"> Get Some Content </div> You may also use window:top and window:bottom to scroll to the top and bottom of the current window. <!-- this will get some content and swap it into the current div, then ensure that the viewport is scrolled to the very top --> <div hx-get="/example" hx-swap="innerHTML show:window:top"> Get Some Content </div> For boosted links and forms the default behaviour is show:top. You can disable it globally with htmx.config.scrollIntoViewOnBoost or you can use hx-swap="show:none" on an element basis. <form action="/example" hx-swap="show:none"> ... </form>

Focus scroll

htmx preserves focus between requests for inputs that have a defined id attribute. By default htmx prevents auto-scrolling to focused inputs between requests which can be unwanted behavior on longer requests when the user has already scrolled away. To enable focus scroll you can use focus-scroll:true. <input id="name" hx-get="/validation" hx-swap="outerHTML focus-scroll:true"/> Alternatively, if you want the page to automatically scroll to the focused element after each request you can change the htmx global configuration value htmx.config.defaultFocusScroll to true. Then disable it for specific requests using focus-scroll:false. <input id="name" hx-get="/validation" hx-swap="outerHTML focus-scroll:false"/>

 Notes

hx-swap is inherited and can be placed on a parent element The default value of this attribute is innerHTML Due to DOM limitations, it’s not possible to use the outerHTML method on the <body> element. htmx will change outerHTML on <body> to use innerHTML. The default swap delay is 0ms The default settle delay is 20ms

hx-sync

The hx-sync attribute allows you to synchronize AJAX requests between multiple elements. The hx-sync attribute consists of a CSS selector to indicate the element to synchronize on, followed optionally by a colon and then by an optional syncing strategy. The available strategies are: drop - drop (ignore) this request if an existing request is in flight (the default) abort - drop (ignore) this request if an existing request is in flight, and, if that is not the case, abort this request if another request occurs while it is still in flight replace - abort the current request, if any, and replace it with this request queue - place this request in the request queue associated with the given element The queue modifier can take an additional argument indicating exactly how to queue: queue first - queue the first request to show up while a request is in flight queue last - queue the last request to show up while a request is in flight queue all - queue all requests that show up while a request is in flight

 Notes

hx-sync is inherited and can be placed on a parent element This example resolves a race condition between a form’s submit request and an individual input’s validation request. Normally, without using hx-sync, filling out the input and immediately submitting the form triggers two parallel requests to /validate and /store. Using hx-sync="closest form:abort" on the input will watch for requests on the form and abort the input’s request if a form request is present or starts while the input request is in flight. <form hx-post="/store"> <input id="title" name="title" type="text" hx-post="/validate" hx-trigger="change" hx-sync="closest form:abort"> <button type="submit">Submit</button> </form> If you’d rather prioritize the validation request over the submit request, you can use the drop strategy. This example will prioritize the validation request over the submit request so that if a validation request is in flight, the form cannot be submitted. <form hx-post="/store"> <input id="title" name="title" type="text" hx-post="/validate" hx-trigger="change" hx-sync="closest form:drop" > <button type="submit">Submit</button> </form> When dealing with forms that contain many inputs, you can prioritize the submit request over all input validation requests using the hx-sync replace strategy on the form tag. This will cancel any in-flight validation requests and issue only the hx-post="/store" request. If you’d rather abort the submit request and prioritize any existing validation requests you can use the hx-sync="this:abort" strategy on the form tag. <form hx-post="/store" hx-sync="this:replace"> <input id="title" name="title" type="text" hx-post="/validate" hx-trigger="change" /> <button type="submit">Submit</button> </form> When implementing active search functionality the hx-trigger attribute’s delay modifier can be used to debounce the user’s input and avoid making multiple requests while the user types. However, once a request is made, if the user begins typing again a new request will begin even if the previous one has not finished processing. This example will cancel any in-flight requests and use only the last request. In cases where the search input is contained within the target, then using hx-sync like this also helps reduce the chances that the input will be replaced while the user is still typing. <input type="search" hx-get="/search" hx-trigger="keyup changed delay:500ms, search" hx-target="#search-results" hx-sync="this:replace">

hx-target

The hx-target attribute allows you to target a different element for swapping than the one issuing the AJAX request. The value of this attribute can be: A CSS query selector of the element to target. this which indicates that the element that the hx-target attribute is on is the target. closest <CSS selector> which will find the closest ancestor element or itself, that matches the given CSS selector (e.g. closest tr will target the closest table row to the element). find <CSS selector> which will find the first child descendant element that matches the given CSS selector. next which resolves to element.nextElementSibling next <CSS selector> which will scan the DOM forward for the first element that matches the given CSS selector. (e.g. next .error will target the closest following sibling element with error class) previous which resolves to element.previousElementSibling previous <CSS selector> which will scan the DOM backwards for the first element that matches the given CSS selector. (e.g previous .error will target the closest previous sibling with error class) Here is an example that targets a div: <div> <div id="response-div"></div> <button hx-post="/register" hx-target="#response-div" hx-swap="beforeend"> Register! </button> </div> The response from the /register url will be appended to the div with the id response-div. This example uses hx-target="this" to make a link that updates itself when clicked: <a hx-post="/new-link" hx-target="this" hx-swap="outerHTML">New link</a>

 Notes

hx-target is inherited and can be placed on a parent element

hx-trigger

The hx-trigger attribute allows you to specify what triggers an AJAX request. A trigger value can be one of the following: An event name (e.g. “click” or “my-custom-event”) followed by an event filter and a set of event modifiers A polling definition of the form every <timing declaration> A comma-separated list of such events

  Standard Events

A standard event, such as click can be specified as the trigger like so: <div hx-get="/clicked" hx-trigger="click">Click Me</div>

Standard Event Filters

Events can be filtered by enclosing a boolean javascript expression in square brackets after the event name. If this expression evaluates to true the event will be triggered, otherwise it will be ignored. <div hx-get="/clicked" hx-trigger="click[ctrlKey]">Control Click Me</div> This event will trigger if a click event is triggered with the event.ctrlKey property set to true. Conditions can also refer to global functions or state <div hx-get="/clicked" hx-trigger="click[checkGlobalState()]">Control Click Me</div> And can also be combined using the standard javascript syntax <div hx-get="/clicked" hx-trigger="click[ctrlKey&&shiftKey]">Control-Shift Click Me</div> Note that all symbols used in the expression will be resolved first against the triggering event, and then next against the global namespace, so myEvent[foo] will first look for a property named foo on the event, then look for a global symbol with the name foo

Standard Event Modifiers

Standard events can also have modifiers that change how they behave. The modifiers are: once - the event will only trigger once (e.g. the first click) changed - the event will only change if the value of the element has changed. Please pay attention change is the name of the event and changed is the name of the modifier. delay:<timing declaration> - a delay will occur before an event triggers a request. If the event is seen again it will reset the delay. throttle:<timing declaration> - a throttle will occur after an event triggers a request. If the event is seen again before the delay completes, it is ignored, the element will trigger at the end of the delay. from:<Extended CSS selector> - allows the event that triggers a request to come from another element in the document (e.g. listening to a key event on the body, to support hot keys) A standard CSS selector resolves to all elements matching that selector. Thus, from:input would listen on every input on the page. The CSS selector is only evaluated once and is not re-evaluated when the page changes. If you need to detect dynamically added elements use an event filter, for example click[event.target.matches('input')] The extended CSS selector here allows for the following non-standard CSS values: document - listen for events on the document window - listen for events on the window closest <CSS selector> - finds the closest ancestor element or itself, matching the given css selector find <CSS selector> - finds the closest child matching the given css selector next resolves to element.nextElementSibling next <CSS selector> scans the DOM forward for the first element that matches the given CSS selector. (e.g. next .error will target the closest following sibling element with error class) previous resolves to element.previousElementSibling previous <CSS selector> scans the DOM backwards for the first element that matches the given CSS selector. (e.g previous .error will target the closest previous sibling with error class) target:<CSS selector> - allows you to filter via a CSS selector on the target of the event. This can be useful when you want to listen for triggers from elements that might not be in the DOM at the point of initialization, by, for example, listening on the body, but with a target filter for a child element consume - if this option is included the event will not trigger any other htmx requests on parents (or on elements listening on parents) queue:<queue option> - determines how events are queued if an event occurs while a request for another event is in flight. Options are: first - queue the first event last - queue the last event (default) all - queue all events (issue a request for each event) none - do not queue new events Here is an example of a search box that searches on keyup, but only if the search value has changed and the user hasn’t typed anything new for 1 second: <input name="q" hx-get="/search" hx-trigger="keyup changed delay:1s" hx-target="#search-results"/> The response from the /search url will be appended to the div with the id search-results.

  Non-standard Events

There are some additional non-standard events that htmx supports: load - triggered on load (useful for lazy-loading something) revealed - triggered when an element is scrolled into the viewport (also useful for lazy-loading). If you are using overflow in css like overflow-y: scroll you should use intersect once instead of revealed. intersect - fires once when an element first intersects the viewport. This supports two additional options: root:<selector> - a CSS selector of the root element for intersection threshold:<float> - a floating point number between 0.0 and 1.0, indicating what amount of intersection to fire the event on

  Triggering via the HX-Trigger header

If you’re trying to fire an event from HX-Trigger response header, you will likely want to use the from:body modifier. E.g. if you send a header like this HX-Trigger: my-custom-event with a response, an element would likely need to look like this: <div hx-get="/example" hx-trigger="my-custom-event from:body"> Triggered by HX-Trigger header... </div> in order to fire. This is because the header will likely trigger the event in a different DOM hierarchy than the element that you wish to be triggered. For a similar reason, you will often listen for hot keys from the body.

  Polling

By using the syntax every <timing declaration> you can have an element poll periodically: <div hx-get="/latest_updates" hx-trigger="every 1s"> Nothing Yet! </div> This example will issue a GET to the /latest_updates URL every second and swap the results into the innerHTML of this div. If you want to add a filter to polling, it should be added after the poll declaration: <div hx-get="/latest_updates" hx-trigger="every 1s [someConditional]"> Nothing Yet! </div>

  Multiple Triggers

Multiple triggers can be provided, separated by commas. Each trigger gets its own options. <div hx-get="/news" hx-trigger="load, click delay:1s"></div> This example will load /news immediately on page load, and then again with a delay of one second after each click.

  Via JavaScript

The AJAX request can be triggered via JavaScript htmx.trigger(), too.

 Notes

hx-trigger is not inherited hx-trigger can be used without an AJAX request, in which case it will only fire the htmx:trigger event In order to pass a CSS selector that contains whitespace (e.g. form input) to the from- or target-modifier, surround the selector in parentheses or curly brackets (e.g. from:(form input) or from:nearest (form input))

hx-validate

The hx-validate attribute will cause an element to validate itself by way of the HTML5 Validation API before it submits a request. Only <form> elements validate data by default, but other elements do not. Adding hx-validate="true" to <input>, <textarea> or <select> enables validation before sending requests.

 Notes

hx-validate is not inherited

hx-vals

The hx-vals attribute allows you to add to the parameters that will be submitted with an AJAX request. By default, the value of this attribute is a list of name-expression values in JSON (JavaScript Object Notation) format. If you wish for hx-vals to evaluate the values given, you can prefix the values with javascript: or js:. <div hx-get="/example" hx-vals='{"myVal": "My Value"}'>Get Some HTML, Including A Value in the Request</div> <div hx-get="/example" hx-vals='js:{myVal: calculateValue()}'>Get Some HTML, Including a Dynamic Value from Javascript in the Request</div> When using evaluated code you can access the event object. This example includes the value of the last typed key within the input. <div hx-get="/example" hx-trigger="keyup" hx-vals='js:{lastKey: event.key}'> <input type="text" /> </div>

 Security Considerations

By default, the value of hx-vals must be valid JSON. It is not dynamically computed. If you use the javascript: prefix, be aware that you are introducing security considerations, especially when dealing with user input such as query strings or user-generated content, which could introduce a Cross-Site Scripting (XSS) vulnerability.

 Notes

hx-vals is inherited and can be placed on a parent element. A child declaration of a variable overrides a parent declaration. Input values with the same name will be overridden by variable declarations.

hx-vars

NOTE: hx-vars has been deprecated in favor of hx-vals, which is safer by default. The hx-vars attribute allows you to dynamically add to the parameters that will be submitted with an AJAX request. The value of this attribute is a comma separated list of name:<expression> values, the same as the internal syntax of javascript Object Literals. <div hx-get="/example" hx-vars="myVar:computeMyVar()">Get Some HTML, Including A Dynamic Value in the Request</div>

 Security Considerations

The expressions in hx-vars are dynamically computed which allows you to add JavaScript code that will be executed. Be careful to never trust user input in your expressions as this may lead to a Cross-Site Scripting (XSS) vulnerability. If you are dealing with user input such as query strings or user-generated content, consider using hx-vals which is a safer alternative.

 Notes

hx-vars is inherited and can be placed on a parent element. A child declaration of a variable overrides a parent declaration. Input values with the same name will be overridden by variable declarations.

HX-Location Response Header

This response header can be used to trigger a client side redirection without reloading the whole page. Instead of changing the page’s location it will act like following a hx-boost link, creating a new history entry, issuing an ajax request to the value of the header and pushing the path into history. A sample response would be: HX-Location: /test Which would push the client to test as if the user had clicked on <a href="/test" hx-boost="true"> If you want to redirect to a specific target on the page rather than the default of document.body, you can pass more details along with the event, by using JSON for the value of the header: HX-Location: {"path":"/test2", "target":"#testdiv"} Path is required and is url to load the response from. The rest of the data mirrors the ajax api context, which is: source - the source element of the request event - an event that “triggered” the request handler - a callback that will handle the response HTML target - the target to swap the response into swap - how the response will be swapped in relative to the target values - values to submit with the request headers - headers to submit with the request select - allows you to select the content you want swapped from a response

HX-Push-Url Response Header

The HX-Push-Url header allows you to push a URL into the browser location history. This creates a new history entry, allowing navigation with the browser’s back and forward buttons. This is similar to the hx-push-url attribute. If present, this header overrides any behavior defined with attributes. The possible values for this header are: A URL to be pushed into the location bar. This may be relative or absolute, as per history.pushState(). false, which prevents the browser’s history from being updated.

HX-Replace-Url Response Header

The HX-Replace-Url header allows you to replace the current URL in the browser location history. This does not create a new history entry; in effect, it removes the previous current URL from the browser’s history. This is similar to the hx-replace-url attribute. If present, this header overrides any behavior defined with attributes. The possible values for this header are: A URL to replace the current URL in the location bar. This may be relative or absolute, as per history.replaceState(), but must have the same origin as the current URL. false, which prevents the browser’s current URL from being updated.

HX-Trigger Response Headers

These response headers can be used to trigger client side actions on the target element within a response to htmx. You can trigger a single event or as many uniquely named events as you would like. The headers are: HX-Trigger - trigger events as soon as the response is received. HX-Trigger-After-Settle - trigger events after the settling step. HX-Trigger-After-Swap - trigger events after the swap step. To trigger a single event with no additional details you can simply send the event name in a header like so: HX-Trigger: myEvent This will trigger myEvent on the triggering element and will bubble up to the body. As an example you could listen for this event like this: document.body.addEventListener("myEvent", function(evt){ alert("myEvent was triggered!"); }) … or like this, if you’re trying to trigger some element without using JS code: <!-- Since it bubbles up to the <body>, we must use the `from:body` modifier below --> <div hx-trigger="myEvent from:body" hx-get="/example"></div> If you want to pass details along with the event, you can move to JSON for the value of the trigger: HX-Trigger: {"showMessage":"Here Is A Message"} To handle this event you would write the following code: document.body.addEventListener("showMessage", function(evt){ alert(evt.detail.value); }) Note that the value of the message was put into the detail.value slot. If you wish to pass multiple pieces of data you can use a nested JSON object on the right hand side of the JSON object: HX-Trigger: {"showMessage":{"level" : "info", "message" : "Here Is A Message"}} And handle this event like so: document.body.addEventListener("showMessage", function(evt){ if(evt.detail.level === "info"){ alert(evt.detail.message); } }) Each property of the JSON object on the right hand side will be copied onto the details object for the event.

  Multiple Triggers

If you wish to invoke multiple events, you can simply add additional properties to the top level JSON object: HX-Trigger: {"event1":"A message", "event2":"Another message"} You may also trigger multiple events with no additional details by sending event names separated by commas, like so: HX-Trigger: event1, event2 Using events gives you a lot of flexibility to add functionality to normal htmx responses.

Javascript API


Method - htmx.addClass()
Method - htmx.ajax()
Method - htmx.closest()
Property - htmx.config
Property - htmx.createEventSource
Property - htmx.createWebSocket
Method - htmx.defineExtension()
Method - htmx.find()
Method - htmx.findAll()
Method - htmx.logAll()
Method - htmx.logNone()
Property - htmx.logger
Method - htmx.off()
Method - htmx.on()
Method - htmx.onLoad()
Method - htmx.parseInterval()
Method - htmx.process()
Method - htmx.remove()
Method - htmx.removeClass()
Method - htmx.removeExtension()
Method - htmx.swap()
Method - htmx.takeClass()
Method - htmx.toggleClass()
Method - htmx.trigger()
Method - htmx.values()
While it is not a focus of the library, htmx does provide a small API of helper methods, intended mainly for extension development or for working with events. The hyperscript project is intended to provide more extensive scripting support for htmx-based applications.

Method - htmx.addClass()

This method adds a class to the given element.
Parameters
elt - the element to add the class to class - the class to add or elt - the element to add the class to class - the class to add delay - delay (in milliseconds ) before class is added
Example
// add the class 'myClass' to the element with the id 'demo' htmx.addClass(htmx.find('#demo'), 'myClass'); // add the class 'myClass' to the element with the id 'demo' after 1 second htmx.addClass(htmx.find('#demo'), 'myClass', 1000);

Method - htmx.ajax()

Issues an htmx-style AJAX request. This method returns a Promise, so a callback can be executed after the content has been inserted into the DOM.
Parameters
verb - ‘GET’, ‘POST’, etc. path - the URL path to make the AJAX element - the element to target (defaults to the body) or verb - ‘GET’, ‘POST’, etc. path - the URL path to make the AJAX selector - a selector for the target or verb - ‘GET’, ‘POST’, etc. path - the URL path to make the AJAX context - a context object that contains any of the following source - the source element of the request, hx-* attrs which affect the request will be resolved against that element and its ancestors event - an event that “triggered” the request handler - a callback that will handle the response HTML target - the target to swap the response into swap - how the response will be swapped in relative to the target values - values to submit with the request headers - headers to submit with the request select - allows you to select the content you want swapped from a response
Example
// issue a GET to /example and put the response HTML into #myDiv htmx.ajax('GET', '/example', '#myDiv') // issue a GET to /example and replace #myDiv with the response htmx.ajax('GET', '/example', {target:'#myDiv', swap:'outerHTML'}) // execute some code after the content has been inserted into the DOM htmx.ajax('GET', '/example', '#myDiv').then(() => { // this code will be executed after the 'htmx:afterOnLoad' event, // and before the 'htmx:xhr:loadend' event console.log('Content inserted successfully!'); });

Method - htmx.closest()

Finds the closest matching element in the given elements parentage, inclusive of the element
Parameters
elt - the element to find the selector from selector - the selector to find
Example
// find the closest enclosing div of the element with the id 'demo' htmx.closest(htmx.find('#demo'), 'div');

Property - htmx.config

A property holding the configuration htmx uses at runtime. Note that using a meta tag is the preferred mechanism for setting these properties.
Properties
attributesToSettle:["class", "style", "width", "height"] - array of strings: the attributes to settle during the settling phase refreshOnHistoryMiss:false - boolean: if set to true htmx will issue a full page refresh on history misses rather than use an AJAX request defaultSettleDelay:20 - int: the default delay between completing the content swap and settling attributes defaultSwapDelay:0 - int: the default delay between receiving a response from the server and doing the swap defaultSwapStyle:'innerHTML' - string: the default swap style to use if hx-swap is omitted historyCacheSize:10 - int: the number of pages to keep in localStorage for history support historyEnabled:true - boolean: whether or not to use history includeIndicatorStyles:true - boolean: if true, htmx will inject a small amount of CSS into the page to make indicators invisible unless the htmx-indicator class is present indicatorClass:'htmx-indicator' - string: the class to place on indicators when a request is in flight requestClass:'htmx-request' - string: the class to place on triggering elements when a request is in flight addedClass:'htmx-added' - string: the class to temporarily place on elements that htmx has added to the DOM settlingClass:'htmx-settling' - string: the class to place on target elements when htmx is in the settling phase swappingClass:'htmx-swapping' - string: the class to place on target elements when htmx is in the swapping phase allowEval:true - boolean: allows the use of eval-like functionality in htmx, to enable hx-vars, trigger conditions & script tag evaluation. Can be set to false for CSP compatibility. allowScriptTags:true - boolean: allows script tags to be evaluated in new content inlineScriptNonce:'' - string: the nonce to add to inline scripts inlineStyleNonce:'' - string: the nonce to add to inline styles withCredentials:false - boolean: allow cross-site Access-Control requests using credentials such as cookies, authorization headers or TLS client certificates timeout:0 - int: the number of milliseconds a request can take before automatically being terminated wsReconnectDelay:'full-jitter' - string/function: the default implementation of getWebSocketReconnectDelay for reconnecting after unexpected connection loss by the event code Abnormal Closure, Service Restart or Try Again Later wsBinaryType:'blob' - string: the the type of binary data being received over the WebSocket connection disableSelector:"[hx-disable], [data-hx-disable]" - array of strings: htmx will not process elements with this attribute on it or a parent scrollBehavior:'smooth' - string: the behavior for a boosted link on page transitions. The allowed values are auto and smooth. Smooth will smoothscroll to the top of the page while auto will behave like a vanilla link. defaultFocusScroll:false - boolean: if the focused element should be scrolled into view, can be overridden using the focus-scroll swap modifier getCacheBusterParam:false - boolean: if set to true htmx will append the target element to the GET request in the format org.htmx.cache-buster=targetElementId globalViewTransitions:false - boolean: if set to true, htmx will use the View Transition API when swapping in new content. methodsThatUseUrlParams:["get"] - array of strings: htmx will format requests with these methods by encoding their parameters in the URL, not the request body selfRequestsOnly:true - boolean: whether to only allow AJAX requests to the same domain as the current document ignoreTitle:false - boolean: if set to true htmx will not update the title of the document when a title tag is found in new content scrollIntoViewOnBoost:true - boolean: whether or not the target of a boosted element is scrolled into the viewport. If hx-target is omitted on a boosted element, the target defaults to body, causing the page to scroll to the top. triggerSpecsCache:null - object: the cache to store evaluated trigger specifications into, improving parsing performance at the cost of more memory usage. You may define a simple object to use a never-clearing cache, or implement your own system using a proxy object |
Example
// update the history cache size to 30 htmx.config.historyCacheSize = 30;

Property - htmx.createEventSource

A property used to create new Server Sent Event sources. This can be updated to provide custom SSE setup.
Value
func(url) - a function that takes a URL string and returns a new EventSource
Example
// override SSE event sources to not use credentials htmx.createEventSource = function(url) { return new EventSource(url, {withCredentials:false}); };

Property - htmx.createWebSocket

A property used to create new WebSocket. This can be updated to provide custom WebSocket setup.
Value
func(url) - a function that takes a URL string and returns a new WebSocket
Example
// override WebSocket to use a specific protocol htmx.createWebSocket = function(url) { return new WebSocket(url, ['wss']); };

Method - htmx.defineExtension()

Defines a new htmx extension.
Parameters
name - the extension name ext - the extension definition
Example
// defines a silly extension that just logs the name of all events triggered htmx.defineExtension("silly", { onEvent : function(name, evt) { console.log("Event " + name + " was triggered!") } });

Method - htmx.find()

Finds an element matching the selector
Parameters
selector - the selector to match or elt - the root element to find the matching element in, inclusive selector - the selector to match
Example
// find div with id my-div var div = htmx.find("#my-div") // find div with id another-div within that div var anotherDiv = htmx.find(div, "#another-div")

Method - htmx.findAll()

Finds all elements matching the selector
Parameters
selector - the selector to match or elt - the root element to find the matching elements in, inclusive selector - the selector to match
Example
// find all divs var allDivs = htmx.findAll("div") // find all paragraphs within a given div var allParagraphsInMyDiv = htmx.findAll(htmx.find("#my-div"), "p")

Method - htmx.logAll()

Log all htmx events, useful for debugging.
Example
htmx.logAll();

Method - htmx.logNone()

Log no htmx events, call this to turn off the debugger if you previously enabled it.
Example
htmx.logNone();

Property - htmx.logger

The logger htmx uses to log with
Value
func(elt, eventName, detail) - a function that takes an element, eventName and event detail and logs it
Example
htmx.logger = function(elt, event, data) { if(console) { console.log("INFO:", event, elt, data); } }

Method - htmx.off()

Removes an event listener from an element
Parameters
eventName - the event name to remove the listener from listener - the listener to remove or target - the element to remove the listener from eventName - the event name to remove the listener from listener - the listener to remove
Example
// remove this click listener from the body htmx.off("click", myEventListener); // remove this click listener from the given div htmx.off("#my-div", "click", myEventListener)

Method - htmx.on()

Adds an event listener to an element
Parameters
eventName - the event name to add the listener for listener - the listener to add or target - the element to add the listener to eventName - the event name to add the listener for listener - the listener to add
Example
// add a click listener to the body var myEventListener = htmx.on("click", function(evt){ console.log(evt); }); // add a click listener to the given div var myEventListener = htmx.on("#my-div", "click", function(evt){ console.log(evt); });

Method - htmx.onLoad()

Adds a callback for the htmx:load event. This can be used to process new content, for example initializing the content with a javascript library
Parameters
callback(elt) - the callback to call on newly loaded content
Example
htmx.onLoad(function(elt){ MyLibrary.init(elt); })

Method - htmx.parseInterval()

Parses an interval string consistent with the way htmx does. Useful for plugins that have timing-related attributes. Caution: Accepts an int followed by either s or ms. All other values use parseFloat
Parameters
str - timing string
Example
// returns 3000 var milliseconds = htmx.parseInterval("3s"); // returns 3 - Caution var milliseconds = htmx.parseInterval("3m");

Method - htmx.process()

Processes new content, enabling htmx behavior. This can be useful if you have content that is added to the DOM outside of the normal htmx request cycle but still want htmx attributes to work.
Parameters
elt - element to process
Example
document.body.innerHTML = "<div hx-get='/example'>Get it!</div>" // process the newly added content htmx.process(document.body);

Method - htmx.remove()

Removes an element from the DOM
Parameters
elt - element to remove or elt - element to remove delay - delay (in milliseconds ) before element is removed
Example
// removes my-div from the DOM htmx.remove(htmx.find("#my-div")); // removes my-div from the DOM after a delay of 2 seconds htmx.remove(htmx.find("#my-div"), 2000);

Method - htmx.removeClass()

Removes a class from the given element
Parameters
elt - element to remove the class from class - the class to remove or elt - element to remove the class from class - the class to remove delay - delay (in milliseconds ) before class is removed
Example
// removes .myClass from my-div htmx.removeClass(htmx.find("#my-div"), "myClass"); // removes .myClass from my-div after 6 seconds htmx.removeClass(htmx.find("#my-div"), "myClass", 6000);

Method - htmx.removeExtension()

Removes the given extension from htmx
Parameters
name - the name of the extension to remove
Example
htmx.removeExtension("my-extension");

Method - htmx.swap()

Performs swapping (and settling) of HTML content
Parameters
target - the HTML element or string selector of swap target content - string representation of content to be swapped swapSpec - swapping specification, representing parameters from hx-swap swapStyle (required) - swapping style (innerHTML, outerHTML, beforebegin etc) swapDelay, settleDelay (number) - delays before swapping and settling respectively transition (bool) - whether to use HTML transitions for swap ignoreTitle (bool) - disables page title updates head (string) - specifies head tag handling strategy (merge or append). Leave empty to disable head handling scroll, scrollTarget, show, showTarget, focusScroll - specifies scroll handling after swap swapOptions - additional optional parameters for swapping select - selector for the content to be swapped (equivalent of hx-select) selectOOB - selector for the content to be swapped out-of-band (equivalent of hx-select-oob) eventInfo - an object to be attached to htmx:afterSwap and htmx:afterSettle elements anchor - an anchor element that triggered scroll, will be scrolled into view on settle. Provides simple alternative to full scroll handling contextElement - DOM element that serves as context to swapping operation. Currently used to find extensions enabled for specific element afterSwapCallback, afterSettleCallback - callback functions called after swap and settle respectively. Take no arguments
Example
// swap #output element inner HTML with div element with "Swapped!" text htmx.swap("#output", "<div>Swapped!</div>", {swapStyle: 'innerHTML'});

Method - htmx.takeClass()

Takes the given class from its siblings, so that among its siblings, only the given element will have the class.
Parameters
elt - the element that will take the class class - the class to take
Example
// takes the selected class from tab2's siblings htmx.takeClass(htmx.find("#tab2"), "selected");

Method - htmx.toggleClass()

Toggles the given class on an element
Parameters
elt - the element to toggle the class on class - the class to toggle
Example
// toggles the selected class on tab2 htmx.toggleClass(htmx.find("#tab2"), "selected");

Method - htmx.trigger()

Triggers a given event on an element
Parameters
elt - the element to trigger the event on name - the name of the event to trigger detail - details for the event
Example
// triggers the myEvent event on #tab2 with the answer 42 htmx.trigger("#tab2", "myEvent", {answer:42});

Method - htmx.values()

Returns the input values that would resolve for a given element via the htmx value resolution mechanism
Parameters
elt - the element to resolve values on request type - the request type (e.g. get or post) non-GET’s will include the enclosing form of the element. Defaults to post
Example
// gets the values associated with this form var values = htmx.values(htmx.find("#myForm"));